/* 包含文件-------------------------------------------------------------------*/
#include <stdlib.h>
#include <stdio.h>
#include "DESAlgorithm.h"
#include "DESAlgorithmTables.h"

BoolType Temp[65] = { ( BoolType ) 0};
BoolType SubKey[16][48] = { ( BoolType ) 0};

/*******************************************************************************
* 函数名           : BitsCopy
* 描述             : 二进制数组复制
* 参数             : 无
* 输入             : DatIn：要复制的二进制数组的地址 len：转换长度
* 输出             : DatOut：存放复制后的二进制数的地址
* 返回             : 无
*******************************************************************************/
void BitsCopy ( BoolType *DatOut, BoolType *DatIn, unsigned char Len ) // 数组复制 OK
{
    unsigned char i;

    for ( i = 0; i < Len; i++ )
    {
        DatOut[i] = DatIn[i];
    }
}
/*-------------------------------
 位转换成字节函数
 字节数组每8次移一位
 位每次向左移 与上一次或
---------------------------------*/
void BitToByte ( unsigned char *DatOut, BoolType *DatIn, int Num ) // OK
{
    int i = 0;

    for ( i = 0; i < ( Num / 8 ); i++ )
    {
        DatOut[i] = 0;
    }

    for ( i = 0; i < Num; i++ )
    {
        DatOut[i / 8] |= DatIn[i] << ( 7 - i % 8 );
    }
}

/*******************************************************************************
* 函数名           : ByteToBit
* 描述             : 字节转换成位，共64位
* 参数             : 无
* 输入             : DatIn：要转换的字节 num：转换长度
* 输出             : DatOut：存放转换成二进制的数据
* 返回             : 无
*******************************************************************************/
void ByteToBit ( BoolType *DatOut, unsigned char *DatIn, unsigned char Num )  // OK
{
    unsigned char i;
#if 0

    for ( i = 0; i < Num; i++ )
    {
        DatOut[i] = ( BoolType ) ( DatIn[i / 8] & 0x80 );
        DatIn[i / 8] = DatIn[i / 8] << 1;

        if ( DatOut[i] == 128 )
        {
            DatOut[i] = ( BoolType ) 1;   //后期优化，不知道为何位为1的地方变成128了，有能力的小伙伴可以改进后给我留言，哈哈，大家分享一下
        }
    }

#endif

    for ( i = 0; i < Num; i++ )
    {
        DatOut[i] = ( BoolType ) ( DatIn[i / 8] >> ( 7 - i % 8 ) ) & 0x01;
    }


}



/*******************************************************************************
* 函数名           : BitToHex
* 描述             : 二进制密文转换为十六进制，共16个字符
* 参数             : 无
* 输入             : DatIn：要转换的二进制密文数据 num：转换长度
* 输出             : DatOut：存放转换成十六进制的密文数据
* 返回             : 无
*******************************************************************************/
void BitToHex ( unsigned char *DatOut, BoolType *DatIn, unsigned char Num )
{
    unsigned char i;
#if 0

    //memset(DatOut,0x00,Num);
    for ( i = 0; i < Num / 4; i++ )
    {
        DatOut[i] = 0;
    }

    for ( i = 0; i < Num / 4; i++ )
    {
        DatOut[i] = ( DatIn[i * 4] << 3 ) + ( DatIn[i * 4 + 1] << 2 )
                    + ( DatIn[i * 4 + 2] << 1 ) + ( DatIn[i * 4 + 3] << 0 );

        if ( ( DatOut[i] % 16 ) > 9 )
        {
            DatOut[i] = DatOut[i] % 16 + '7'; //  余数大于9时处理将10-15换成A-F
        }
        else
        {
            DatOut[i] = DatOut[i] % 16 + '0';
        }
    }

#endif

    for ( i = 0; i < Num / 8; i++ )
    {
        DatOut[i] = 0;
    }

    for ( i = 0; i < Num / 8; i++ )
    {
        DatOut[i] = ( DatIn[i * 8] << 7 ) | ( DatIn[i * 8 + 1] << 6 ) | ( DatIn[i * 8 + 2] << 5 ) + ( DatIn[i * 8 + 3] << 4 ) | ( DatIn[i * 8 + 4] << 3 ) | ( DatIn[i * 8 + 5] << 2 ) | ( DatIn[i * 8 + 6] << 1 ) + ( DatIn[i * 8 + 7] << 0 );
    }


}

/*---------------------------------------------
十六进制字符转二进制
----------------------------------------------*/
void HexToBit ( BoolType *DatOut, unsigned char *DatIn, unsigned int Num )
{
    int i = 0; // 字符型输入
#if 0

    for ( i = 0; i < Num; i++ )
    {
        if ( ( DatIn[i / 4] ) > '9' ) // 大于9
        {
            DatOut[i] = ( BoolType ) ( ( ( DatIn[i / 4] - '7' ) >> ( 3 - i % 4 ) ) & 0x01 );
        }
        else
        {
            DatOut[i] = ( BoolType ) ( ( ( DatIn[i / 4] - '0' ) >> ( 3 - i % 4 ) ) & 0x01 );
        }
    }

#endif

    for ( i = 0; i < Num; i++ )
    {
        DatOut[i] = ( DatIn[i / 8] >> ( 7 - i % 8 ) ) & 0x01;
    }

}



/*******************************************************************************
* 函数名           : TablePermute
* 描述             : PC-1置换
* 参数             : 无
* 输入             : DatIn：要置换的二进制数据 Table：PC-1置换表 num：置换的长度(56)
* 输出             : DatOut：存放置换后的二进制数据
* 返回             : 无
*******************************************************************************/
void TablePermute ( BoolType *DatOut, BoolType *DatIn, const unsigned char *Table, unsigned char Num )
{
    unsigned char i;
    //static BoolType Temp[256]={0};

    for ( i = 0; i < Num; i++ )      // Num为置换的长度
    {
        Temp[i] = DatIn[Table[i] - 1]; // 原来的数据按对应的表上的位置排列
    }

    BitsCopy ( DatOut, Temp, Num );  // 把缓存Temp的值赋给DatOut
}


/*******************************************************************************
* 函数名           : LoopMove
* 描述             : 子密钥Cn，Dn的移位操作
* 参数             : 无
* 输入             : DatIn：移位前数据地址 Len：移位前数据长度 PC-1置换表 Num：要移Num位(具体查阅移位表)
* 输出             : DatOut：存放置换后的二进制数据
* 返回             : 无
*******************************************************************************/
void LoopMove ( BoolType *DatIn, unsigned int Len, unsigned char Num ) // 循环左移 Len数据长度 Num移动位数
{
    //static BoolType Temp[256]={0};            //static BoolType Temp[256]={0};    // 缓存   OK

    BitsCopy ( Temp, DatIn, Num );      // 将数据最左边的Num位(被移出去的)存入Temp
    BitsCopy ( DatIn, DatIn + Num, Len - Num ); // 将数据左边开始的第Num移入原来的空间
    BitsCopy ( DatIn + Len - Num, Temp, Num ); // 将缓存中移出去的数据加到最右边
}


/*******************************************************************************
* 函数名           : Xor
* 描述             : E(Rn-1)异或Kn
* 参数             : 无
* 输入             : DatA：E(Rn-1)数据的地址 DatB：新密钥Kn数据的地址 Num：位数
* 输出             : DatA：异或后的结果
* 返回             : 无
*******************************************************************************/
void Xor ( BoolType *DatA, BoolType *DatB, unsigned char Num )      // 异或函数
{
    unsigned char i;

    for ( i = 0; i < Num; i++ )
    {
        DatA[i] = ( BoolType ) ( DatA[i] ^ DatB[i] );         // 异或
    }
}


/*******************************************************************************
* 函数名           : S_Change
* 描述             : S盒操作，将8组6比特的数据转换为8组4比特的数据
* 参数             : 无
* 输入             : DatIn：8组6比特的数据(即异或后的结果)48个元素的数组
* 输出             : DatOut：8组4比特的数据；32个元素的数组
* 返回             : 无
*******************************************************************************/
void S_Change ( BoolType *DatOut, BoolType *DatIn ) // S盒变换
{
    unsigned char i, j;
    unsigned char X, Y;                                     // i为8个S盒

    for ( i = 0, Y = 0, X = 0; i < 8; i++, DatIn += 6, DatOut += 4 ) // 每执行一次,输入数据偏移6位
    {
        // 每执行一次,输出数据偏移4位
        Y = ( DatIn[0] << 1 ) + DatIn[5];                   // af代表第几行--第1位和最后1位为S盒的行
        X = ( DatIn[1] << 3 ) + ( DatIn[2] << 2 ) + ( DatIn[3] << 1 ) + DatIn[4]; // bcde代表第几列--中间4位为S盒的列

        for ( j = 0; j < 4; j++ )
        {
            DatOut[j] = ( BoolType ) ( ( S_Box[i][Y][X] << j ) & 0x08 ); // 把找到的点数据换为二进制

            if ( DatOut[j] == 8 )
            {
                DatOut[j] = ( BoolType ) 1; //这个跟前面也是一样，位为1的地方变成了8，有能力的小伙伴告诉我哈
            }
        }
    }
}


/*******************************************************************************
* 函数名           : F_Change
* 描述             : F函数工作过程：1.通过E表将32位Rn-1拓展成48位 2.对输出E(Rn-1) 和秘钥Kn执行异或运算 3.将2步的结果通过S盒将8组6比特变成8组4比特 4.将3结果进行P变换
* 参数             : 无
* 输入             : DatIn：Rn-1 32个元素数组；DatKi：新密钥Kn, 48个元素数组
* 输出             : DatIn:最后P置换的结果
* 返回             : 无
*******************************************************************************/
void F_Change ( BoolType *DatIn, BoolType *DatKi )   // F函数
{
    BoolType MiR[48] = { ( BoolType ) 0};        // 输入32位通过E选位变为48位

    TablePermute ( MiR, DatIn, E_Table, 48 ); //--OK

    Xor ( MiR, DatKi, 48 );               // 和子密钥异或--OK

    S_Change ( DatIn, MiR );              // S盒变换--OK

    TablePermute ( DatIn, DatIn, P_Table, 32 ); // P置换后输出--OK
}

/*******************************************************************************
* 函数名           : SetKey
* 描述             : 产生子密钥：1.56位的PC-1置换 2.拆分密钥为C0,D0，各28位 3.对Cn，Dn按表移位 4.拼凑密钥Cn，Dn组成Kn新密钥
* 参数             : 无
* 输入             : KeyIn：8字节的原始密钥
* 输出             : SubKey：新密钥Kn
* 返回             : 无
*******************************************************************************/
void SetKey ( unsigned char *KeyIn )                       // 设置密钥 获取子密钥Ki
{
    unsigned char i;
    BoolType KeyBit[64] = { ( BoolType ) 0};                 // 密钥二进制存储空间
    BoolType *KiL = &KeyBit[0], *KiR = &KeyBit[28]; // 前28,后28共56位

    ByteToBit ( KeyBit, KeyIn, 64 );               // 把密钥转为二进制存入KeyBit--ok

    TablePermute ( KeyBit, KeyBit, PC1_Table, 56 ); // PC1表置换 56次--ok

    //16轮迭代
    for ( i = 0; i < 16; i++ ) //k1-k16
    {
        LoopMove ( KiL, 28, Move_Table[i] );  // 前28位左移

        LoopMove ( KiR, 28, Move_Table[i] );  // 后28位左移 -- OK

        TablePermute ( SubKey[i], KeyBit, PC2_Table, 48 );  //PC-2置换-- OK

        // 二维数组 SubKey[i]为每一行起始地址
        // 每移一次位进行PC2置换得 Ki 48位
    }
}

/*******************************************************************************
* 函数名           : PlayDes
* 描述             : 加密数据过程：1.IP置换 2.16轮迭代 a)Ln=Rn-1
                                                       b)Rn=Ln-1+f(Rn-1,Kn)
* 参数             : 无
* 输入             : MesIn：8字节明文
* 输出             : MesOut：存放DES运算后8字节的密文
* 返回             : 无
*******************************************************************************/
void PlayDes ( unsigned char *MesOut, unsigned char *MesIn ) // 执行DES加密
{
    unsigned char i;// 字节输入 Bin运算 Hex输出
    BoolType MesBit[64] = { ( BoolType ) 0};  // 明文二进制存储空间 64位
    BoolType Temp[32] = { ( BoolType ) 0};
    BoolType *MiL = &MesBit[0], *MiR = &MesBit[32]; // 前32位 后32位

    ByteToBit ( MesBit, MesIn, 64 );            // 把明文换成二进制存入MesBit--OK

    TablePermute ( MesBit, MesBit, IP_Table, 64 ); // IP置换--OK

    for ( i = 0; i < 16; i++ )                   // 迭代16次
    {
        BitsCopy ( Temp, MiR, 32 );        // 临时存储--公式(a)
        F_Change ( MiR, SubKey[i] );       // F函数变换
        Xor ( MiR, MiL, 32 );              // 得到Ri--公式(b)
        BitsCopy ( MiL, Temp, 32 );        // 得到Li ---OK
    }

    BitsCopy ( Temp, MiR, 32 );
    BitsCopy ( MiR, MiL, 32 );
    BitsCopy ( MiL, Temp, 32 ); //最后的R16L16不调换

    TablePermute ( MesBit, MesBit, IPR_Table, 64 ); //得到R16L16后进行IP-1(IP逆变换)

    BitToHex ( MesOut, MesBit, 64 );            //二进制转换成16进制--OK
}


/*******************************************************************************
* 函数名           : KickDes
* 描述             : 加密数据过程：1.IP置换 2.16轮迭代 a)Ln=Rn-1
                                                       b)Rn=Ln-1+f(Rn-1,Kn)
* 参数             : 无
* 输入             : MesIn：8字节明文
* 输出             : MesOut：存放DES运算后8字节的密文
* 返回             : 无
*******************************************************************************/
void KickDes ( unsigned char *MesOut, unsigned char *MesIn )    // 执行DES解密
{
    // Hex输入 Bin运算 字节输出
    int i = 0;
    static BoolType MesBit[64] = { ( BoolType ) 0};  // 密文二进制存储空间 64位
    static BoolType Temp[32] = { ( BoolType ) 0};
    static BoolType *MiL = &MesBit[0], *MiR = &MesBit[32]; // 前32位 后32位
    HexToBit ( MesBit, MesIn, 64 );            // 把密文换成二进制存入MesBit
    TablePermute ( MesBit, MesBit, IP_Table, 64 ); // IP置换

    for ( i = 15; i >= 0; i-- )
    {
        BitsCopy ( Temp, MiR, 32 );
        F_Change ( MiR, SubKey[i] );
        Xor ( MiR, MiL, 32 );
        BitsCopy ( MiL, Temp, 32 );
    }

    BitsCopy ( Temp, MiR, 32 );
    BitsCopy ( MiR, MiL, 32 );
    BitsCopy ( MiL, Temp, 32 );

    TablePermute ( MesBit, MesBit, IPR_Table, 64 );
    BitToByte ( MesOut, MesBit, 64 );
}


void Play3Des ( unsigned char *MesOut, unsigned char *MesIn,unsigned char *PwdL,unsigned char *PwdR ) // 执行3DES加密
{
	unsigned char MesBack[8];
	SetKey(PwdL);
	PlayDes ( MesOut, MesIn );
	SetKey(PwdR);
	KickDes (MesBack,MesOut);
	SetKey(PwdL);
	PlayDes ( MesOut, MesBack );
}
//执行DES加密  IN通过KEY以后变成OUT 参数KEY请自己控制为8位
void DO_DES(unsigned char *MesIn, unsigned char *KeyIn ,unsigned char *MesOut)
{
	SetKey(KeyIn);
  PlayDes(MesOut,MesIn );
}

void UNDO_DES(unsigned char *MesIn, unsigned char *KeyIn ,unsigned char *MesOut)
{
	SetKey(KeyIn);
    KickDes(MesOut,MesIn );
}

//执行3DES加密  IN通过KEY以后变成OUT 参数KEY请自己控制为16位
void DO_3DES(unsigned char *MesIn, unsigned char *KeyIn ,unsigned char *MesOut)
{
	unsigned char PwdL[8];
	unsigned char PwdR[8];
	unsigned char i=0;
	for(i=0;i<8;i++)
	PwdL[i]=KeyIn[i];
	for(i=0;i<8;i++)
	PwdR[i]=KeyIn[i+8];
    Play3Des ( MesOut, MesIn,PwdL,PwdR); 
}

void UNDO_3DES(unsigned char *MesIn, unsigned char *KeyIn ,unsigned char *MesOut)
{
	unsigned char MesBack[8];
	unsigned char PwdL[8];
	unsigned char PwdR[8];
	unsigned char i=0;
	for(i=0;i<8;i++)
	PwdL[i]=KeyIn[i];
	for(i=0;i<8;i++)
	PwdR[i]=KeyIn[i+8];
	

	
	SetKey(PwdL);
	KickDes ( MesOut, MesIn );
	SetKey(PwdR);
	PlayDes (MesBack,MesOut);
	SetKey(PwdL);
	KickDes ( MesOut, MesBack );
}
